/**
 * 
 */
package database.datastructure;

import java.io.Serializable;
import java.util.ArrayList;
import java.util.Comparator;
import java.util.List;

/**
 * Only one of the nodePointers or dataRecords will be used,
 * depending on whether it is leaf or non-leaf node.
 * @author Sravan
 *
 */
public class Node<K extends Comparable<K>,V> implements Serializable{
	
	private int size;
	//private int number_of_keys;
	private List<K> searchKeys;
	private List<Node<K,V>> nodePointers;
	private List<V> dataRecords;
	private boolean isLeafNode;
	private Node<K,V> nextLeafNode;
	private Node<K,V> prevLeafNode;
	
	public int no_of_keys(){
		return searchKeys.size();
	}
	
	public int numberOfNodePointers(){
		return nodePointers.size();
	}

	/**
	 * @return the nextLeafNode
	 */
	public Node<K, V> getNextLeafNode() {
		return nextLeafNode;
	}

	/**
	 * @param nextLeafNode the nextLeafNode to set
	 */
	public void setNextLeafNode(Node<K, V> nextLeafNode) {
		this.nextLeafNode = nextLeafNode;
	}

	/**
	 * @return the prevLeafNode
	 */
	public Node<K, V> getPrevLeafNode() {
		return prevLeafNode;
	}

	/**
	 * @param prevLeafNode the prevLeafNode to set
	 */
	public void setPrevLeafNode(Node<K, V> prevLeafNode) {
		this.prevLeafNode = prevLeafNode;
	}

	/**
	 * @return the isLeafNode
	 */
	public boolean isLeafNode() {
		return isLeafNode;
	}

	/**
	 * @param isLeafNode the isLeafNode to set
	 */
	public void setLeafNode(boolean isLeafNode) {
		this.isLeafNode = isLeafNode;
	}

	/**
	 * @return the nodePointers
	 */
	public List<Node<K, V>> getNodePointers() {
		return nodePointers;
	}

	public List<K> getSearchKeys() {
		return searchKeys;
	}

	public List<V> getDataRecords() {
		return dataRecords;
	}

	public boolean isALeafNode(){
		return isLeafNode;
	}
	
	public Node(){
		this(8);
		//number_of_keys = 0;
	}
	
	public Node(int size){
		this.size = size;
		searchKeys = new ArrayList<K>();
		nodePointers = new ArrayList<Node<K,V>>();
		dataRecords = new ArrayList<V>();
		isLeafNode = true;
		//number_of_keys = 0;
	}
	
	public boolean isFull(){
		return (searchKeys.size() >= size); 
	}
	
	public boolean isEmpty(){
		return (searchKeys.size() == 0);
	}
	
	/**
	 * This operation must be sorted insert.
	 * As the keys are sorted with in the Node.
	 * @param key
	 * @return
	 */
	public boolean addSearchKey(K key){
		if(!isFull()){
			int index = 0;
			for(K key1:searchKeys){
				if(key.compareTo(key1) < 0){
					break;
				}
				index++;
			}
			searchKeys.add(index,key);
			return true;
		}
		return false;
	}
	
	public void addSearchKey(int index,K key){
		searchKeys.add(index, key);
	}
	
	public boolean hasKey(K key){
		return searchKeys.contains(key);
	}
	
	/**
	 * This handle remove search key. Reordering required after removal.
	 * @param key
	 * @return
	 */
	public boolean removeSearchKey(K key){
		if(hasKey(key)){
			searchKeys.remove(key);
			return true;
		}
		return false;
	}
	
	public K getSearchKey(int index){
		return searchKeys.get(index);
	}
	
	public void addNodePointer(Node node){
		nodePointers.add(node);
	}
	
	public void addNodePointer(int index, Node node){
		nodePointers.add(index,node);
	}
	
	public Node<K,V> removeNodePointer(int index){
		return nodePointers.remove(index);
	}
	
	public void addDataRecord(V record){
		dataRecords.add(record);
	}
	
	public V removeDataRecord(int index){
		return dataRecords.remove(index);
	}
	
	public Node<K,V> getNodePointer(int index){
		return nodePointers.get(index);
	}
	
	public K removeSearchKey(int index){
		return searchKeys.remove(index);
	}
	
	public void addDataRecord(int index,V record){
		dataRecords.add(index, record);
	}
	
	public V getDataRecord(int index){
		return dataRecords.get(index);
	}
	
}
